#include <stdint.h>
#include <stdio.h>
#include "system.h"
#include <string.h>
#include "io.h"
#include "arm32.h"
#include "sys_dram.h"
#include "spi_flash.h"
#include "f1c100s_de.h"
#include "f1c100s_intc.h"
#include "f1c100s_timer.h"
#include "f1c100s_gpio.h"
#include "f1c100s_uart.h"
#include "system.h"

#define MAX_RX_BUF (8*1024*1024) 

uint32_t re_count = 0;
uint8_t *rx_data = (uint8_t *)0x80000000;
//uint8_t rx_data[MAX_RX_BUF];

void uart1_irq_handler(void)
{
    uint32_t it_status = uart_get_status(UART1);
    if (it_status & UART_LSR_DR)
    {
        //rx_flag = 1;
        rx_data[re_count] = uart_get_rx(UART1);
        // uart_tx(UART1, rx_data);
        re_count++;
        re_count = re_count % MAX_RX_BUF;
    }
}
void uart_irq_init()
{
    intc_enable_irq(IRQ_UART1);
    uart_enable_interrupt(UART1, UART_IEN_RBF);
    intc_set_irq_handler(IRQ_UART1, uart1_irq_handler);
}


void dump_regs(uint32_t addr, uint32_t len);
void reset_cpu(void);

#define FW_START_ADDR 0x10000
#define FW_MAGIC 0x555AAAFF

typedef struct
{
    uint32_t jump_instr;
    uint32_t magic;
    uint32_t start;
    uint32_t end;
    uint32_t reserved;
    uint32_t crc32;
} fw_header_t;
void bootload_reset()
{
    intc_disable_irq(IRQ_UART1);
	arm32_interrupt_disable(); 

}
int main(void)
{
    //uint16_t i=0;
    uint8_t dram_size=0;
    uint32_t last_count=0;
	fw_header_t *hdr=(fw_header_t *)rx_data;
    system_init();
	//gpio_init(GPIOE,PIN0,GPIO_MODE_OUTPUT,GPIO_PULL_NONE,GPIO_DRV_3);
    
	dram_size=sys_dram_init();
    printf("DRAM size:%uMB\r\n",dram_size);
	/*
	for(i=0;i<200;i++)
		rx_data[i]=i;

	for(i=0;i<200;i++)
		printf("%04d ",rx_data[i]);
	printf("\r\n");
	*/
	arm32_interrupt_enable(); // Enable interrupts
    uart_irq_init();
    printf("SPL_bootloader started compiled_time:%s %s\r\n", __DATE__, __TIME__);
    while(1)
    {
        delay_soft(200);
        //gpio_pin_toggle(GPIOE,0);
		if(re_count)
		{
			if(re_count==last_count)
			{
				printf("re_count=%ld\r\n",re_count);
				if ((hdr->magic == FW_MAGIC) && (hdr->end > hdr->start))
				{
					uint32_t len = hdr->end - hdr->start;
					printf("app header OK! length=%ld \r\n",len);
					__asm__ __volatile__("ldr pc, =0x80000000" : : : "memory");
					bootload_reset();
				}
				else
				{
					printf("No valid header found\r\n");
					// __asm__ __volatile__("ldr pc, =0x10000" : : : "rom");
				}
				re_count=0;
			}
		}
		last_count=re_count;
    }
    /*
    gpio_init(GPIOF, PIN0 | PIN1 | PIN3 | PIN5, GPIO_MODE_AF3, GPIO_PULL_NONE, GPIO_DRV_3);
    printf("JTAG enabled, use pin:PF0 PF1 PF3 PF5 .\r\n");

    uint8_t size = sys_dram_init();
    printf("DRAM size: %uMB\r\n", size);

    spi_flash_init();
    uint32_t id = spi_flash_read_id();
    printf("SPI flash ID: %06lX\r\n", id);

    // uint8_t read[1024];
    // spi_flash_read(0, read, 1024);
    // for (int i = 0; i < 1024; i++)
    // {
    //     printf("%02X ", read[i]);
    //     if ((i + 1) % 8 == 0)
    //         printf("\r\n");
    // }

    spi_flash_read(FW_START_ADDR, dram, sizeof(fw_header_t));
    fw_header_t *hdr = (fw_header_t *)dram;
    if ((hdr->magic == FW_MAGIC) && (hdr->end > hdr->start))
    {
        uint32_t len = hdr->end - hdr->start;
        printf("app header OK! app length: %lu\r\n", len);
        spi_flash_read(FW_START_ADDR, dram, len);
        printf("copy to dram done, bootloader app.\r\n");
        __asm__ __volatile__("ldr pc, =0x80000000" : : : "memory");
    }
    else
    {
        printf("No valid header found\r\n");
        // __asm__ __volatile__("ldr pc, =0x10000" : : : "rom");
    }

    while (1)
    {
    }
    */
    return 0;
}

void dump_regs(uint32_t addr, uint32_t len)
{
    for (uint32_t i = addr; i < addr + len; i += 4)
    {
        printf("%08lX: %08lX\r\n", i, read32(i));
    }
}

void reset_cpu(void)
{
    arm32_interrupt_disable();
    wdg_init(WDG_MODE_RESET, WDG_INTV_500MS);
    while (1)
        ;
}
